﻿using System.Globalization;
using System.Runtime.CompilerServices;


namespace LxBasic
{
    public struct Float128 : IComparable<Float128>, IComparable, IEquatable<Float128>, IConvertible, IFormattable
    {
        internal readonly double x0;

        internal readonly double x1;

        public static Float128 Zero => new Float128(0.0);

        public static Float128 One => new Float128(1.0);

        public double High => x0;

        public double Low => x1;

        internal double this[int index]
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                switch (index)
                {
                    case 0: return x0;
                    case 1: return x1;
                    default: throw new IndexOutOfRangeException();
                }
            }
        }

        public Float128(double x0, double x1 = 0.0)
        {
            this.x0 = x0;
            this.x1 = x1;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator +(Float128 left, Float128 right)
        {
            (double sum0, double error0) = FloatMathHelper.TwoSum(left.x0, right.x0);
            (double sum1, double error1) = FloatMathHelper.TwoSum(left.x1, right.x1);
            return Renormalize(sum0, error0, sum1, error1);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator +(Float128 left, double right)
        {
            (double sum, double error) = FloatMathHelper.TwoSum(left.x0, right);
            return FloatMathHelper.QuickTwoSumD(sum, error + left.x1);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator +(double left, Float128 right)
        {
            return right + left;
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 Add(double a, double b)
        {
            return FloatMathHelper.TwoSumD(a, b);
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 AddSloppy(Float128 one, Float128 other)
        {
            (double sum0, double error0) = FloatMathHelper.TwoSum(one.x0, other.x0);
            return FloatMathHelper.QuickTwoSumD(sum0, error0 + one.x1 + other.x1);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator -(Float128 value)
        {
            return new Float128(-value.x0, -value.x1);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator -(Float128 left, Float128 right)
        {
            (double sum0, double error0) = FloatMathHelper.TwoDiff(left.x0, right.x0);
            (double sum1, double error1) = FloatMathHelper.TwoDiff(left.x1, right.x1);
            return Renormalize(sum0, error0, sum1, error1);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator -(Float128 left, double right)
        {
            (double sum, double error) = FloatMathHelper.TwoDiff(left.x0, right);
            return FloatMathHelper.QuickTwoSumD(sum, error + left.x1);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator -(double left, Float128 right)
        {
            (double sum, double error) = FloatMathHelper.TwoDiff(left, right.x0);
            return FloatMathHelper.QuickTwoSumD(sum, error - right.x1);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 Subtract(double a, double b)
        {
            (double sum, double error) = FloatMathHelper.TwoDiff(a, b);
            return new Float128(sum, error);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 SubtractSloppy(Float128 one, Float128 other)
        {
            (double sum, double error) = FloatMathHelper.TwoDiff(one.x0, other.x0);
            return FloatMathHelper.QuickTwoSumD(sum, error + one.x1 - other.x1);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator *(Float128 left, Float128 right)
        {
            (double product, double error) = FloatMathHelper.TwoProd(left.x0, right.x0);
            return FloatMathHelper.QuickTwoSumD(product, error + left.x1 * right.x0 + left.x1 * right.x0);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator *(Float128 left, double right)
        {
            (double product, double error) = FloatMathHelper.TwoProd(left.x0, right);
            return FloatMathHelper.QuickTwoSumD(product, error + left.x1 * right);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator *(double left, Float128 right)
        {
            return right * left;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 Multiply(double a, double b)
        {
            (double product, double error) = FloatMathHelper.TwoProd(a, b);
            return new Float128(product, error);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator /(Float128 left, Float128 right)
        {
            double num = left.x0 / right.x0;
            if (double.IsInfinity(num))
            {
                return new Float128(num);
            }

            Float128 left2 = left - num * right;
            double num2 = left2.x0 / right.x0;
            double right2 = (left2 - num2 * right).x0 / right.x0;
            return FloatMathHelper.QuickTwoSumD(num, num2) + right2;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator /(Float128 left, double right)
        {
            double num = left.x0;
            double num2 = num / right;
            if (double.IsInfinity(num2))
            {
                return new Float128(num2);
            }

            (double product1, double error1) = FloatMathHelper.TwoProd(num2, right);
            (double sum2, double error2) = FloatMathHelper.TwoDiff(num, product1);
            error2 += left.x1;
            error2 -= error1;
            return FloatMathHelper.QuickTwoSumD(num2, (sum2 + error2) / right);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 operator /(double left, Float128 right)
        {
            return (Float128)left / right;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Float128 Divide(double a, double b)
        {
            double num = a / b;
            if (double.IsInfinity(num))
            {
                return new Float128(num);
            }

            (double product1, double error1) = FloatMathHelper.TwoProd(num, b);
            (double sum2, double error2) = FloatMathHelper.TwoDiff(a, product1);
            error2 -= error1;
            return FloatMathHelper.QuickTwoSumD(num, (sum2 + error2) / b);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool IsNaN()
        {
            return double.IsNaN(x0) | double.IsNaN(x1);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool IsInfinity()
        {
            return double.IsInfinity(x0);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool IsFinite()
        {
            return !(double.IsInfinity(x0) | double.IsNaN(x0));
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool IsPositiveInfinity()
        {
            return double.IsPositiveInfinity(x0);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool IsNegativeInfinity()
        {
            return double.IsNegativeInfinity(x0);
        }

        //public static explicit operator DdReal(QdReal value)
        //{
        //    return new DdReal(value.x0, value.x1);
        //}

        public static explicit operator Float128(decimal value)
        {
            return new Float128((double)value);
        }

        public static implicit operator Float128(double value)
        {
            return new Float128(value);
        }

        public static implicit operator Float128(float value)
        {
            return new Float128(value);
        }

        public static implicit operator Float128(ulong value)
        {
            return new Float128(value);
        }

        public static implicit operator Float128(long value)
        {
            return new Float128(value);
        }

        public static implicit operator Float128(uint value)
        {
            return new Float128(value);
        }

        public static implicit operator Float128(int value)
        {
            return new Float128(value);
        }

        public static implicit operator Float128(short value)
        {
            return new Float128(value);
        }

        public static implicit operator Float128(ushort value)
        {
            return new Float128(value);
        }

        public static implicit operator Float128(byte value)
        {
            return new Float128(value);
        }

        public static implicit operator Float128(sbyte value)
        {
            return new Float128(value);
        }

        public static implicit operator Float128(char value)
        {
            return new Float128(value);
        }

        public static explicit operator decimal(Float128 value)
        {
            return (decimal)value.x0 + (decimal)value.x1;
        }

        public static explicit operator double(Float128 value)
        {
            return value.x0;
        }

        public static explicit operator float(Float128 value)
        {
            return (float)value.x0;
        }

        public static explicit operator ulong(Float128 value)
        {
            return (ulong)value.x0;
        }

        public static explicit operator long(Float128 value)
        {
            return (long)value.x0;
        }

        public static explicit operator uint(Float128 value)
        {
            return (uint)value.x0;
        }

        public static explicit operator int(Float128 value)
        {
            return (int)value.x0;
        }

        public static explicit operator short(Float128 value)
        {
            return (short)value.x0;
        }

        public static explicit operator ushort(Float128 value)
        {
            return (ushort)value.x0;
        }

        public static explicit operator byte(Float128 value)
        {
            return (byte)value.x0;
        }

        public static explicit operator sbyte(Float128 value)
        {
            return (sbyte)value.x0;
        }

        public static explicit operator char(Float128 value)
        {
            return (char)value.x0;
        }

        TypeCode IConvertible.GetTypeCode()
        {
            return TypeCode.Double;
        }

        bool IConvertible.ToBoolean(IFormatProvider provider)
        {
            throw new InvalidCastException("Cannot cast DdReal to bool");
        }

        byte IConvertible.ToByte(IFormatProvider provider)
        {
            return (byte)this;
        }

        char IConvertible.ToChar(IFormatProvider provider)
        {
            return (char)this;
        }

        DateTime IConvertible.ToDateTime(IFormatProvider provider)
        {
            throw new InvalidCastException("Cannot cast DdReal to DateTime");
        }

        decimal IConvertible.ToDecimal(IFormatProvider provider)
        {
            return (decimal)this;
        }

        double IConvertible.ToDouble(IFormatProvider provider)
        {
            return (double)this;
        }

        short IConvertible.ToInt16(IFormatProvider provider)
        {
            return (short)this;
        }

        int IConvertible.ToInt32(IFormatProvider provider)
        {
            return (int)this;
        }

        long IConvertible.ToInt64(IFormatProvider provider)
        {
            return (long)this;
        }

        sbyte IConvertible.ToSByte(IFormatProvider provider)
        {
            return (sbyte)this;
        }

        float IConvertible.ToSingle(IFormatProvider provider)
        {
            return (float)this;
        }

        object IConvertible.ToType(Type conversionType, IFormatProvider provider)
        {
            //if (conversionType == typeof(QdReal))
            //{
            //    return (QdReal)this;
            //}

            if (conversionType == typeof(object))
            {
                return this;
            }

            if (Type.GetTypeCode(conversionType) != TypeCode.Object)
            {
                return Convert.ChangeType(this, Type.GetTypeCode(conversionType), provider);
            }

            throw new InvalidCastException($"Converting type \"{typeof(Float128)}\" to type \"{conversionType.Name}\" is not supported.");
        }

        ushort IConvertible.ToUInt16(IFormatProvider provider)
        {
            return (ushort)this;
        }

        uint IConvertible.ToUInt32(IFormatProvider provider)
        {
            return (uint)this;
        }

        ulong IConvertible.ToUInt64(IFormatProvider provider)
        {
            return (ulong)this;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator ==(Float128 left, Float128 right)
        {
            return left.Equals(right);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator !=(Float128 left, Float128 right)
        {
            return !left.Equals(right);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator <(Float128 left, Float128 right)
        {
            return left.CompareTo(right) < 0;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator >(Float128 left, Float128 right)
        {
            return left.CompareTo(right) > 0;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator <=(Float128 left, Float128 right)
        {
            return left.CompareTo(right) <= 0;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static bool operator >=(Float128 left, Float128 right)
        {
            return left.CompareTo(right) >= 0;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public int CompareTo(Float128 other)
        {
            double num = x0;
            int num2 = num.CompareTo(other.x0);
            if (num2 != 0)
            {
                return num2;
            }

            num = x1;
            return num.CompareTo(other.x1);
        }

        public int CompareTo(object obj)
        {
            if (obj == null)
            {
                return 1;
            }

            if (obj is Float128)
            {
                Float128 other = (Float128)obj;
                return CompareTo(other);
            }

            throw new ArgumentException("Object must be of type DdReal");
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public bool Equals(Float128 other)
        {
            double num = x0;
            if (num.Equals(other.x0))
            {
                num = x1;
                return num.Equals(other.x1);
            }

            return false;
        }

        public override bool Equals(object obj)
        {
            if (obj is Float128)
            {
                Float128 other = (Float128)obj;
                return Equals(other);
            }

            return false;
        }

        public override int GetHashCode()
        {
            double num = x0;
            int num2 = num.GetHashCode() * 397;
            num = x1;
            return num2 ^ num.GetHashCode();
        }

        public static Float128 Parse(string s)
        {
            if (TryParse(s, out Float128 value))
            {
                return value;
            }

            throw new FormatException();
        }

        public static bool TryParse(string s, out Float128 value)
        {
            int num = 0;
            int num2 = 0;
            int num3 = -1;
            int num4 = 0;
            int result = 0;
            bool flag = false;
            Float128 ddReal = value = 0.0;
            while (!flag && num != s.Length)
            {
                char c = s[num++];
                if (char.IsDigit(c))
                {
                    int num5 = c - 48;
                    ddReal = ddReal * 10.0 + num5;
                    num4++;
                    continue;
                }

                switch (c)
                {
                    case '.':
                        if (num3 >= 0)
                        {
                            return false;
                        }

                        num3 = num4;
                        break;
                    case '+':
                    case '-':
                        if (num2 != 0 || num4 > 0)
                        {
                            return false;
                        }

                        num2 = c != '-' ? 1 : -1;
                        break;
                    case 'E':
                    case 'e':
                        if (!int.TryParse(s.Substring(num), out result))
                        {
                            return false;
                        }

                        flag = true;
                        break;
                    default:
                        return false;
                }
            }

            if (num3 >= 0)
            {
                result -= num4 - num3;
            }

            if (result != 0)
            {
                ddReal *= Math.Pow(10.0, result);
            }

            value = num2 == -1 ? -ddReal : ddReal;
            return num > 0;
        }

        public override string ToString()
        {
            return ToString("G", CultureInfo.CurrentCulture);
        }

        public string ToString(IFormatProvider provider)
        {
            return ToString("G", provider);
        }

        public string ToString(string format, IFormatProvider formatProvider)
        {
            if (formatProvider == null)
            {
                formatProvider = CultureInfo.CurrentCulture;
            }

            double num = x0;
            return num.ToString(format, formatProvider);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public (double high, double low) Deconstruct()
        {
            return (x0, x1);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private static Float128 Renormalize(double s1, double s2, double t1, double t2)
        {
            s2 += t1;
            (double sum, double error) = FloatMathHelper.QuickTwoSum(s1, s2);
            s1 = sum;
            s2 = error;
            s2 += t2;
            return FloatMathHelper.QuickTwoSumD(s1, s2);
        }
    }
}
//原文件
//public struct DdReal : IComparable<DdReal>, IComparable, IEquatable<DdReal>, IConvertible, IFormattable
//{
//    internal readonly double x0;

//    internal readonly double x1;

//    public static DdReal Zero => new DdReal(0.0);

//    public static DdReal One => new DdReal(1.0);

//    public double High => x0;

//    public double Low => x1;

//    internal double this[int index]
//    {
//        [MethodImpl(MethodImplOptions.AggressiveInlining)]
//        get
//        {
//            switch (index)
//            {
//                case 0:
//                    return x0;
//                case 1:
//                    return x1;
//                default:
//                    throw new IndexOutOfRangeException();
//            }
//        }
//    }

//    public DdReal(double x0, double x1 = 0.0)
//    {
//        this.x0 = x0;
//        this.x1 = x1;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator +(DdReal left, DdReal right)
//    {
//        (double sum, double error) tuple = MathHelper.TwoSum(left.x0, right.x0);
//        double item = tuple.sum;
//        double item2 = tuple.error;
//        (double sum, double error) tuple2 = MathHelper.TwoSum(left.x1, right.x1);
//        double item3 = tuple2.sum;
//        double item4 = tuple2.error;
//        return Renormalize(item, item2, item3, item4);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator +(DdReal left, double right)
//    {
//        (double sum, double error) tuple = MathHelper.TwoSum(left.x0, right);
//        double item = tuple.sum;
//        double item2 = tuple.error;
//        return MathHelper.QuickTwoSumD(item, item2 + left.x1);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator +(double left, DdReal right)
//    {
//        return right + left;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal Add(double a, double b)
//    {
//        return MathHelper.TwoSumD(a, b);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public DdReal Add(double other)
//    {
//        return this + other;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public DdReal Add(DdReal other)
//    {
//        return this + other;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public DdReal AddSloppy(DdReal other)
//    {
//        (double sum, double error) tuple = MathHelper.TwoSum(x0, other.x0);
//        double item = tuple.sum;
//        double item2 = tuple.error;
//        return MathHelper.QuickTwoSumD(item, item2 + x1 + other.x1);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator -(DdReal value)
//    {
//        return new DdReal(0.0 - value.x0, 0.0 - value.x1);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator -(DdReal left, DdReal right)
//    {
//        (double sum, double error) tuple = MathHelper.TwoDiff(left.x0, right.x0);
//        double item = tuple.sum;
//        double item2 = tuple.error;
//        (double sum, double error) tuple2 = MathHelper.TwoDiff(left.x1, right.x1);
//        double item3 = tuple2.sum;
//        double item4 = tuple2.error;
//        return Renormalize(item, item2, item3, item4);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator -(DdReal left, double right)
//    {
//        (double sum, double error) tuple = MathHelper.TwoDiff(left.x0, right);
//        double item = tuple.sum;
//        double item2 = tuple.error;
//        return MathHelper.QuickTwoSumD(item, item2 + left.x1);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator -(double left, DdReal right)
//    {
//        (double sum, double error) tuple = MathHelper.TwoDiff(left, right.x0);
//        double item = tuple.sum;
//        double item2 = tuple.error;
//        return MathHelper.QuickTwoSumD(item, item2 - right.x1);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal Subtract(double a, double b)
//    {
//        (double sum, double error) tuple = MathHelper.TwoDiff(a, b);
//        double item = tuple.sum;
//        double item2 = tuple.error;
//        return new DdReal(item, item2);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public DdReal Subtract(double other)
//    {
//        return this - other;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public DdReal Subtract(DdReal other)
//    {
//        return this - other;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public DdReal SubtractSloppy(DdReal other)
//    {
//        (double sum, double error) tuple = MathHelper.TwoDiff(x0, other.x0);
//        double item = tuple.sum;
//        double item2 = tuple.error;
//        return MathHelper.QuickTwoSumD(item, item2 + x1 - other.x1);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator *(DdReal left, DdReal right)
//    {
//        (double product, double error) tuple = MathHelper.TwoProd(left.x0, right.x0);
//        double item = tuple.product;
//        double item2 = tuple.error;
//        return MathHelper.QuickTwoSumD(item, item2 + left.x1 * right.x0 + left.x1 * right.x0);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator *(DdReal left, double right)
//    {
//        (double product, double error) tuple = MathHelper.TwoProd(left.x0, right);
//        double item = tuple.product;
//        double item2 = tuple.error;
//        return MathHelper.QuickTwoSumD(item, item2 + left.x1 * right);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator *(double left, DdReal right)
//    {
//        return right * left;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal Multiply(double a, double b)
//    {
//        (double product, double error) tuple = MathHelper.TwoProd(a, b);
//        double item = tuple.product;
//        double item2 = tuple.error;
//        return new DdReal(item, item2);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public DdReal Multiply(double other)
//    {
//        return this * other;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public DdReal Multiply(DdReal other)
//    {
//        return this * other;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public DdReal MultiplySloppy(DdReal other)
//    {
//        return this * other;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator /(DdReal left, DdReal right)
//    {
//        double num = left.x0 / right.x0;
//        if (double.IsInfinity(num))
//        {
//            return new DdReal(num);
//        }

//        DdReal left2 = left - num * right;
//        double num2 = left2.x0 / right.x0;
//        double right2 = (left2 - num2 * right).x0 / right.x0;
//        return MathHelper.QuickTwoSumD(num, num2) + right2;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator /(DdReal left, double right)
//    {
//        double num = left.x0;
//        double num2 = num / right;
//        if (double.IsInfinity(num2))
//        {
//            return new DdReal(num2);
//        }

//        (double product, double error) tuple = MathHelper.TwoProd(num2, right);
//        double item = tuple.product;
//        double item2 = tuple.error;
//        (double sum, double error) tuple2 = MathHelper.TwoDiff(num, item);
//        double item3 = tuple2.sum;
//        double item4 = tuple2.error;
//        item4 += left.x1;
//        item4 -= item2;
//        return MathHelper.QuickTwoSumD(num2, (item3 + item4) / right);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal operator /(double left, DdReal right)
//    {
//        return (DdReal)left / right;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static DdReal Divide(double a, double b)
//    {
//        double num = a / b;
//        if (double.IsInfinity(num))
//        {
//            return new DdReal(num);
//        }

//        (double product, double error) tuple = MathHelper.TwoProd(num, b);
//        double item = tuple.product;
//        double item2 = tuple.error;
//        (double sum, double error) tuple2 = MathHelper.TwoDiff(a, item);
//        double item3 = tuple2.sum;
//        double item4 = tuple2.error;
//        item4 -= item2;
//        return MathHelper.QuickTwoSumD(num, (item3 + item4) / b);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public DdReal Divide(double other)
//    {
//        return this / other;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public DdReal Divide(DdReal other)
//    {
//        return this / other;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public DdReal DivideSloppy(DdReal other)
//    {
//        return this / other;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public bool IsNaN()
//    {
//        return double.IsNaN(x0) | double.IsNaN(x1);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public bool IsInfinity()
//    {
//        return double.IsInfinity(x0);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public bool IsFinite()
//    {
//        return !(double.IsInfinity(x0) | double.IsNaN(x0));
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public bool IsPositiveInfinity()
//    {
//        return double.IsPositiveInfinity(x0);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public bool IsNegativeInfinity()
//    {
//        return double.IsNegativeInfinity(x0);
//    }

//    public static explicit operator DdReal(QdReal value)
//    {
//        return new DdReal(value.x0, value.x1);
//    }

//    public static explicit operator DdReal(decimal value)
//    {
//        return new DdReal((double)value);
//    }

//    public static implicit operator DdReal(double value)
//    {
//        return new DdReal(value);
//    }

//    public static implicit operator DdReal(float value)
//    {
//        return new DdReal(value);
//    }

//    public static implicit operator DdReal(ulong value)
//    {
//        return new DdReal(value);
//    }

//    public static implicit operator DdReal(long value)
//    {
//        return new DdReal(value);
//    }

//    public static implicit operator DdReal(uint value)
//    {
//        return new DdReal(value);
//    }

//    public static implicit operator DdReal(int value)
//    {
//        return new DdReal(value);
//    }

//    public static implicit operator DdReal(short value)
//    {
//        return new DdReal(value);
//    }

//    public static implicit operator DdReal(ushort value)
//    {
//        return new DdReal((int)value);
//    }

//    public static implicit operator DdReal(byte value)
//    {
//        return new DdReal((int)value);
//    }

//    public static implicit operator DdReal(sbyte value)
//    {
//        return new DdReal(value);
//    }

//    public static implicit operator DdReal(char value)
//    {
//        return new DdReal((int)value);
//    }

//    public static explicit operator decimal(DdReal value)
//    {
//        return (decimal)value.x0 + (decimal)value.x1;
//    }

//    public static explicit operator double(DdReal value)
//    {
//        return value.x0;
//    }

//    public static explicit operator float(DdReal value)
//    {
//        return (float)value.x0;
//    }

//    public static explicit operator ulong(DdReal value)
//    {
//        return (ulong)value.x0;
//    }

//    public static explicit operator long(DdReal value)
//    {
//        return (long)value.x0;
//    }

//    public static explicit operator uint(DdReal value)
//    {
//        return (uint)value.x0;
//    }

//    public static explicit operator int(DdReal value)
//    {
//        return (int)value.x0;
//    }

//    public static explicit operator short(DdReal value)
//    {
//        return (short)value.x0;
//    }

//    public static explicit operator ushort(DdReal value)
//    {
//        return (ushort)value.x0;
//    }

//    public static explicit operator byte(DdReal value)
//    {
//        return (byte)value.x0;
//    }

//    public static explicit operator sbyte(DdReal value)
//    {
//        return (sbyte)value.x0;
//    }

//    public static explicit operator char(DdReal value)
//    {
//        return (char)value.x0;
//    }

//    TypeCode IConvertible.GetTypeCode()
//    {
//        return TypeCode.Double;
//    }

//    bool IConvertible.ToBoolean(IFormatProvider provider)
//    {
//        throw new InvalidCastException("Cannot cast DdReal to bool");
//    }

//    byte IConvertible.ToByte(IFormatProvider provider)
//    {
//        return (byte)this;
//    }

//    char IConvertible.ToChar(IFormatProvider provider)
//    {
//        return (char)this;
//    }

//    DateTime IConvertible.ToDateTime(IFormatProvider provider)
//    {
//        throw new InvalidCastException("Cannot cast DdReal to DateTime");
//    }

//    decimal IConvertible.ToDecimal(IFormatProvider provider)
//    {
//        return (decimal)this;
//    }

//    double IConvertible.ToDouble(IFormatProvider provider)
//    {
//        return (double)this;
//    }

//    short IConvertible.ToInt16(IFormatProvider provider)
//    {
//        return (short)this;
//    }

//    int IConvertible.ToInt32(IFormatProvider provider)
//    {
//        return (int)this;
//    }

//    long IConvertible.ToInt64(IFormatProvider provider)
//    {
//        return (long)this;
//    }

//    sbyte IConvertible.ToSByte(IFormatProvider provider)
//    {
//        return (sbyte)this;
//    }

//    float IConvertible.ToSingle(IFormatProvider provider)
//    {
//        return (float)this;
//    }

//    object IConvertible.ToType(Type conversionType, IFormatProvider provider)
//    {
//        if (conversionType == typeof(QdReal))
//        {
//            return (QdReal)this;
//        }

//        if (conversionType == typeof(object))
//        {
//            return this;
//        }

//        if (Type.GetTypeCode(conversionType) != TypeCode.Object)
//        {
//            return Convert.ChangeType(this, Type.GetTypeCode(conversionType), provider);
//        }

//        throw new InvalidCastException($"Converting type \"{typeof(DdReal)}\" to type \"{conversionType.Name}\" is not supported.");
//    }

//    ushort IConvertible.ToUInt16(IFormatProvider provider)
//    {
//        return (ushort)this;
//    }

//    uint IConvertible.ToUInt32(IFormatProvider provider)
//    {
//        return (uint)this;
//    }

//    ulong IConvertible.ToUInt64(IFormatProvider provider)
//    {
//        return (ulong)this;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static bool operator ==(DdReal left, DdReal right)
//    {
//        return left.Equals(right);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static bool operator !=(DdReal left, DdReal right)
//    {
//        return !left.Equals(right);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static bool operator <(DdReal left, DdReal right)
//    {
//        return left.CompareTo(right) < 0;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static bool operator >(DdReal left, DdReal right)
//    {
//        return left.CompareTo(right) > 0;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static bool operator <=(DdReal left, DdReal right)
//    {
//        return left.CompareTo(right) <= 0;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public static bool operator >=(DdReal left, DdReal right)
//    {
//        return left.CompareTo(right) >= 0;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public int CompareTo(DdReal other)
//    {
//        double num = x0;
//        int num2 = num.CompareTo(other.x0);
//        if (num2 != 0)
//        {
//            return num2;
//        }

//        num = x1;
//        return num.CompareTo(other.x1);
//    }

//    public int CompareTo(object obj)
//    {
//        if (obj == null)
//        {
//            return 1;
//        }

//        if (obj is DdReal)
//        {
//            DdReal other = (DdReal)obj;
//            return CompareTo(other);
//        }

//        throw new ArgumentException("Object must be of type DdReal");
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public bool Equals(DdReal other)
//    {
//        double num = x0;
//        if (num.Equals(other.x0))
//        {
//            num = x1;
//            return num.Equals(other.x1);
//        }

//        return false;
//    }

//    public override bool Equals(object obj)
//    {
//        if (obj is DdReal)
//        {
//            DdReal other = (DdReal)obj;
//            return Equals(other);
//        }

//        return false;
//    }

//    public override int GetHashCode()
//    {
//        double num = x0;
//        int num2 = num.GetHashCode() * 397;
//        num = x1;
//        return num2 ^ num.GetHashCode();
//    }

//    public static DdReal Parse(string s)
//    {
//        if (TryParse(s, out DdReal value))
//        {
//            return value;
//        }

//        throw new FormatException();
//    }

//    public static bool TryParse(string s, out DdReal value)
//    {
//        int num = 0;
//        int num2 = 0;
//        int num3 = -1;
//        int num4 = 0;
//        int result = 0;
//        bool flag = false;
//        DdReal ddReal = value = 0.0;
//        while (!flag && num != s.Length)
//        {
//            char c = s[num++];
//            if (char.IsDigit(c))
//            {
//                int num5 = c - 48;
//                ddReal = ddReal * 10.0 + num5;
//                num4++;
//                continue;
//            }

//            switch (c)
//            {
//                case '.':
//                    if (num3 >= 0)
//                    {
//                        return false;
//                    }

//                    num3 = num4;
//                    break;
//                case '+':
//                case '-':
//                    if (num2 != 0 || num4 > 0)
//                    {
//                        return false;
//                    }

//                    num2 = ((c != '-') ? 1 : (-1));
//                    break;
//                case 'E':
//                case 'e':
//                    if (!int.TryParse(s.Substring(num), out result))
//                    {
//                        return false;
//                    }

//                    flag = true;
//                    break;
//                default:
//                    return false;
//            }
//        }

//        if (num3 >= 0)
//        {
//            result -= num4 - num3;
//        }

//        if (result != 0)
//        {
//            ddReal *= Math.Pow(10.0, result);
//        }

//        value = ((num2 == -1) ? (-ddReal) : ddReal);
//        return num > 0;
//    }

//    public override string ToString()
//    {
//        return ToString("G", CultureInfo.CurrentCulture);
//    }

//    public string ToString(IFormatProvider provider)
//    {
//        return ToString("G", provider);
//    }

//    public string ToString(string format, IFormatProvider formatProvider)
//    {
//        if (formatProvider == null)
//        {
//            formatProvider = CultureInfo.CurrentCulture;
//        }

//        double num = x0;
//        return num.ToString(format, formatProvider);
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    public void Deconstruct(out double high, out double low)
//    {
//        high = x0;
//        low = x1;
//    }

//    [MethodImpl(MethodImplOptions.AggressiveInlining)]
//    private static DdReal Renormalize(double s1, double s2, double t1, double t2)
//    {
//        s2 += t1;
//        (double sum, double error) tuple = MathHelper.QuickTwoSum(s1, s2);
//        s1 = tuple.sum;
//        s2 = tuple.error;
//        s2 += t2;
//        return MathHelper.QuickTwoSumD(s1, s2);
//    }
//}